const isOperator = value => '+-*/()×÷'.indexOf(value) > -1;

const isNumber = value => value.match(/\d/g);

const getPrioraty = value => {
    if (value == '-' || value == '+') return 1;
    if (value == '*' || value == '/' || value == '×' || value == '÷') return 2;
    return 0;
}

const isPrioraty = (v1, v2) => getPrioraty(v1) <= getPrioraty(v2);

const outputRpn = exp => {
    let inputStack = [];
    let outputStack = [];
    let outputQueue = [];
    exp.replace(/\s/g, '');
    for (let i = 0; i < exp.length; i++) {
        if (!isOperator(exp[i]) &&
            ((!isOperator(exp[i - 1]) && i != 0) ||
                (i == 1 && exp[i - 1] == '-') ||
                (i > 1 && exp[i - 1] == '-' && '+-*/×÷('.indexOf(exp[i - 2]) > -1))) {
            inputStack[inputStack.length - 1] += (exp[i] + '');
        } else {
            inputStack.push(exp[i]);
        }
    }
    while (inputStack.length > 0) {
        let cur = inputStack.shift();
        if (isOperator(cur)) {
            if (cur == '(') {
                outputStack.push(cur);
            } else if (cur == ')') {
                let pop = outputStack.pop();
                while (pop != '(' && outputStack.length > 0) {
                    outputQueue.push(pop);
                    pop = outputStack.pop();
                }
            } else {
                while (isPrioraty(cur, outputStack[outputStack.length - 1]) &&
                    outputStack.length > 0) {
                    outputQueue.push(outputStack.pop())
                }
                outputStack.push(cur);
            }
        } else {
            outputQueue.push(Number(cur));
        }
    }
    if (outputStack.length > 0) {
        while (outputStack.length > 0) {
            outputQueue.push(outputStack.pop());
        }
    }
    return outputQueue;
}

/**
 * 防止精度丢失，重新定义加
 */
const add = (arg1, arg2) => {
    let r1, r2, m;
    try { r1 = arg1.toString().split(".")[1].length } catch (e) { r1 = 0 }
    try { r2 = arg2.toString().split(".")[1].length } catch (e) { r2 = 0 }
    m = Math.pow(10, Math.max(r1, r2))
    return (arg1 * m + arg2 * m) / m 
}

/**
 * 防止精度丢失，重新定义减
 */
const sub = (arg1, arg2) => {
    let r1, r2, m, n;
    try { r1 = arg1.toString().split(".")[1].length } catch (e) { r1 = 0 }
    try { r2 = arg2.toString().split(".")[1].length } catch (e) { r2 = 0 }
    m = Math.pow(10, Math.max(r1, r2));
    n = (r1 >= r2) ? r1 : r2;
    return ((arg1 * m - arg2 * m) / m).toFixed(n); 
}

/**
 * 防止精度丢失，重新定义乘
 */
const mul = (arg1, arg2) => {
    let m = 0, s1 = arg1.toString(), s2 = arg2.toString();
    try { m += s1.split(".")[1].length } catch (e) { }
    try { m += s2.split(".")[1].length } catch (e) { }
    return Number(s1.replace(".", "")) * Number(s2.replace(".", "")) / Math.pow(10, m)
}  

/**
 * 防止精度丢失，重新定义除
 */
const div = (arg1, arg2) => {
    let t1 = 0, t2 = 0, r1, r2;
    try { t1 = arg1.toString().split(".")[1].length } catch (e) { }
    try { t2 = arg2.toString().split(".")[1].length } catch (e) { }
    r1 = Number(arg1.toString().replace(".", ""))
    r2 = Number(arg2.toString().replace(".", ""))
    return mul((r1 / r2), Math.pow(10, t2 - t1));
}

const calRpnExp = rpnArr => {
    let stack = [];
    for (let i = 0, max = rpnArr.length; i < max; i++) {
        if (!isOperator(rpnArr[i])) {
            stack.push(rpnArr[i]);
        } else {
            let num1 = stack.pop();
            let num2 = stack.pop();
            let num = 0;
            if (rpnArr[i] == '-') {
                num = sub(num2, num1);
            } else if (rpnArr[i] == '+') {
                num = add(num2 , num1);
            } else if (rpnArr[i] == '*' || rpnArr[i] == '×') {
                num = mul(num2,num1);
            } else if (rpnArr[i] == '/' || rpnArr[i] == '÷') {
                num = div(num2 , num1);
            }
            stack.push(num);
        }
    }
    return stack[0];
}

const calCommonExp = exp => calRpnExp(outputRpn(exp));

const canLeftParentheses = exp => {
    if (exp != 0 && exp.match(/[[\d\.]$/g)) return false;
    return true;
}

const canRightParentheses = exp => {
    if ('+-×÷*/('.indexOf(exp.charAt(exp.length - 1)) > -1 ||
        exp.split('(').length == exp.split(')').length) return false;
    return true;
}

const canDot = exp => {
    if (exp.match(/((\.\d*)|\))$/g)) return false;
    return true
}

const canOperator = exp => {
    if (exp.charAt(exp.length - 1) == '-' ||
        exp.match(/[\(\.]$/g)) return false;
    return true;
}

const canEqual = exp => {
    if (exp == '0' ||
        exp.split('(').length != exp.split(')').length) return false;
    return true;
}

module.exports = {
    isOperator: isOperator,
    getPrioraty: getPrioraty,
    outputRpn: outputRpn,
    calRpnExp: calRpnExp,
    calCommonExp: calCommonExp,
    canLeftParentheses: canLeftParentheses,
    canRightParentheses: canRightParentheses,
    canDot: canDot,
    canOperator: canOperator,
    canEqual: canEqual
}